package cc.shacocloud.luanniao.core.service.impl

import cc.shacocloud.luanniao.core.exception.ForbiddenException
import cc.shacocloud.luanniao.core.exception.NamespaceStatusAbnormalException
import cc.shacocloud.luanniao.core.exception.UserStatusAbnormalException
import cc.shacocloud.luanniao.core.model.constant.UserNamespaceRoleEnum
import cc.shacocloud.luanniao.core.model.dto.input.NamespaceInput
import cc.shacocloud.luanniao.core.model.mo.UserNamespaceMo
import cc.shacocloud.luanniao.core.model.po.NamespacePo
import cc.shacocloud.luanniao.core.model.po.RefUserNamespacePo
import cc.shacocloud.luanniao.core.model.po.UserPo
import cc.shacocloud.luanniao.core.repository.NamespaceRepository
import cc.shacocloud.luanniao.core.repository.RefUserNamespaceRepository
import cc.shacocloud.luanniao.core.service.NamespaceService
import cc.shacocloud.luanniao.core.service.UserService
import cc.shacocloud.luanniao.core.utils.QueryExpand.findOne
import kotlinx.coroutines.reactor.awaitSingle
import kotlinx.coroutines.reactor.awaitSingleOrNull
import org.springframework.data.relational.core.query.Criteria
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

/**
 * 命名空间服务
 * @author 思追(shaco)
 */
@Service
@Transactional
class NamespaceServiceImpl(
    val namespaceRepository: NamespaceRepository,
    val refUserNamespaceRepository: RefUserNamespaceRepository,
    val userService: UserService,
) : NamespaceService {

    /**
     * 根据id查询命名空间
     */
    override suspend fun findById(namespaceId: Long): NamespacePo? {
        return namespaceRepository.findById(namespaceId).awaitSingleOrNull()
    }

    /**
     * 创建命名空间
     */
    override suspend fun create(input: NamespaceInput, userPo: UserPo): NamespacePo {
        var namespacePo = NamespacePo(
            name = input.name,
            description = input.description
        )
        namespacePo = namespaceRepository.save(namespacePo).awaitSingle()

        // 创建者默认为 owner 权限
        val refUserNamespacePo = RefUserNamespacePo(
            userId = requireNotNull(userPo.id),
            namespaceId = requireNotNull(namespacePo.id),
            role = UserNamespaceRoleEnum.OWNER
        )
        refUserNamespaceRepository.save(refUserNamespacePo).awaitSingle()
        return namespacePo
    }

    /**
     * 获取用户命名空间信息，如果该用户没有命名空间的权限将抛出例外
     */
    override suspend fun findUserNamespace(namespaceId: Long, userId: Long): UserNamespaceMo {
        val criteria = Criteria.where("userId").`is`(userId)
            .and("namespaceId").`is`(namespaceId)
        val refUserNamespacePo = refUserNamespaceRepository.findOne(criteria)

        if (refUserNamespacePo != null) {
            val userPo = userService.findById(userId) ?: throw UserStatusAbnormalException()
            val namespacePo = findById(namespaceId) ?: throw NamespaceStatusAbnormalException()
            return UserNamespaceMo(
                user = userPo,
                namespace = namespacePo,
                role = refUserNamespacePo.role
            )
        }

        throw ForbiddenException()
    }
}